﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BrokerBase.Lib.Person;
using BrokerBase.Lib.Product;
using BrokerBase.Lib.Base;
using NHibernate;
using BrokerBase.Lib.Tool;

namespace BrokerBase.Lib.Policy
{
    public class Policy:BasePolicy, IPolicy
    {
        private IProduct product;

        private IDictionary<string, bool> settingLocks = new Dictionary<string, bool>();

        //private double[] fees;

        public Policy():base()
        {
            SelectedColRateFactors =new  Dictionary<string,string>();
            SelectedRowRateFactors = new Dictionary<string, string>();
            SelectedAdjRateItems = new Dictionary<string, string>();

            OverInsurancePeriod = 1;
            OverPaymentPeriod = 1;
        }

        public Policy(IScheme scheme)
            : this()
        {
            this.Owner = scheme;
        }

        public Policy(IScheme scheme, ProductType pType):this(scheme)
        {
            this.ProductType = pType;
        }

        public virtual IProduct Product 
        {
            get { return this.product; }
            set
            {
                this.product = value;
                this.ProductType = product == null ? 0 : product.ProductType;
            }
        }

        public virtual IBasicAmount SelectedBasicAmount { get; set; }

        public virtual IPaymentPeriod SelectedPaymentPeriod { get; set; }

        public virtual IInsurancePeriod SelectedInsurancePeriod { get; set; }

        //public virtual ITimeUnit SelectedTimeUnit { get; set; }

        //public virtual double Amount { get; set; }

        public override double Fee 
        {
            get
            {
                if (SelectedBasicAmount == null)
                    return 0;
                else
                    return FixFee * AdjRateCoefficient;
            }

            set { /*Nothing*/ }

        }

        public virtual double[] Fees
        {
            get
            {
                double[] fees = null;

                if (FixFees !=null)
                {
                    fees = new double[FixFees.Count()];
                    for (int i = 0; i < fees.Count(); i++)
                    {
                        fees[i] = FixFees[i] * AdjRateCoefficient;
                    }
                }

                return fees;
            }
        }

        public virtual double TimeUnitFee 
        {
            get
            {
                if (SelectedTimeUnit == null)
                    return 0;
                else
                    return Fee / SelectedTimeUnit.Coefficient;
            }
        }

        public virtual double FixFee { get; set; }


        public virtual double[] FixFees { get; set; }

        public virtual double AllFixFees { get; set; }

        public override double TotalFee 
        {
            get
            {
                if (FixFees == null)
                    return 0;
                else
                    return Fees.Sum() ;
                        
            }

            set {/*Nothing*/ }
        }

        public virtual IDictionary<string,string> SelectedColRateFactors { get; set; }

        public virtual IDictionary<string,string> SelectedRowRateFactors { get; set; }

        public virtual IDictionary<string, string> SelectedAdjRateItems { get; set; }

        public virtual void SetSettingLock(string name, bool aLock)
        {
            settingLocks[name] = aLock;
        }

        public virtual bool GetSettingLock(string name)
        {
            KeyValuePair<string, bool> k = settingLocks.FirstOrDefault(p => p.Key == name);

            return k.Value;
        }

        public virtual void SettingLockClear()
        {
            settingLocks.Clear();
        }

        public virtual string GetSelectedRateFactorItem(string rateFactorName, RateFactorAxis axis)
        {
            IDictionary<string, string> dict = null;

            if (axis == RateFactorAxis.Col)
                dict = SelectedColRateFactors;
            else
                dict = SelectedRowRateFactors;

            return dict.FirstOrDefault(p => p.Key == rateFactorName).Value;
        }

        public virtual string GetColKey()
        {
            string[] array = new string[SelectedColRateFactors.Count];

            foreach (var v in SelectedColRateFactors)
            {
                IList<IRateFactor> rfs=Product.ColRateFactors;

                int index = rfs.IndexOf(rfs.First(p => p.Name == v.Key));

                array[index] = v.Value;
            }

            string key = null;

            foreach (var s in array)
            {
                key+=key==null?s:"-"+s;
            }

            return key;
        }

        public virtual RatePos GetRatePos(IList<string> colRateKeys,string key)
        {
            int index = -1;

            index = colRateKeys.IndexOf(key);

            int warpIndex = index / 100;

            int colIndex = index % 100;

            string key1 = string.Empty;
            string key2 = string.Empty;

            if(SelectedRowRateFactors.Count>0)
                key1 = SelectedRowRateFactors[Product.RowRateFactors[0].Name];

            if (SelectedRowRateFactors.Count > 1)
                key2 = SelectedRowRateFactors[Product.RowRateFactors[1].Name] + string.Empty;

            RatePos rp= new RatePos();
            rp.IsMatch = index == -1 ? false : true;
            rp.Key1 = key1;
            rp.Key2 = key2;

            rp.ColIndex = colIndex;
            rp.WarpIndex = warpIndex;

            return rp;
        }

        public virtual double AdjRateCoefficient
        {
            get
            {
                double coff = 1;
                foreach (var a in SelectedAdjRateItems)
                {
                    IAdjustRate adj = Product.AdjustRates.First(p => p.Name == a.Key);

                    IAdjustRateItem item = adj.Items.First(p => p.Name == a.Value);

                    coff *= item.GetCoefficient(this);
                }

                return coff;
            }
            
        }


        public virtual int OverPaymentPeriod { get; set; }

        public virtual int OverInsurancePeriod { get; set; }



        public virtual int Id { get; set; }

        public virtual void SettingDefault()
        {
            SelectedBasicAmount = Product.BasicAmounts[0];//默认第一个基本费率 

            ITimeUnit baseTu = Product.PaymentCycles.FirstOrDefault(p => p.IsBaseUnit);
            SelectedTimeUnit = baseTu == null ? Product.PaymentCycles.First() : baseTu;

            //如果付款期或缴费期只有一个，当然就选这一个。
            if (Product.PaymentPeriods.Count == 1)
                SelectedPaymentPeriod = Product.PaymentPeriods[0];

            if (Product.InsurancePeriods.Count == 1)
                SelectedInsurancePeriod = Product.InsurancePeriods[0];

            if (Product.ProductType == ProductType.Extra)
            {
                IPolicy basic=Owner.BasicPolicy;

                IList<IPaymentPeriod> pps=Product.PaymentPeriods;
                bool isOneYear = pps.Count == 1 && pps[0].Style == PaymentPeriodStyle.Period && pps[0].Value == 1;

                IRelation rel = Product.Relations.First(p => p.Basic.Id ==basic.Product.Id);

                if (isOneYear)
                {
                    OverPaymentPeriod = basic.PaymentPeriodLength;
                    OverInsurancePeriod = OverPaymentPeriod;
                }
                else
                {
                    IDictionary<IPaymentPeriod, int> dpp = new Dictionary<IPaymentPeriod, int>();

                    IPaymentPeriod fristPP=Product.PaymentPeriods[0];

                    KeyValuePair<IPaymentPeriod, int> maxpp = new KeyValuePair<IPaymentPeriod, int>(fristPP, GetPaymentPeriodLength(fristPP, Owner.InsurantAge));

                    int basicPaymentPeriodLength=Owner.BasicPolicy.PaymentPeriodLength;

                    foreach (IPaymentPeriod pp in Product.PaymentPeriods)
                    {
                        
                        KeyValuePair<IPaymentPeriod,int> kpp=new KeyValuePair<IPaymentPeriod,int>(pp,GetPaymentPeriodLength(pp,Owner.InsurantAge));

                        if(maxpp.Value <0 ||( kpp.Value<=basicPaymentPeriodLength && kpp.Value>=maxpp.Value))
                        {
                            maxpp=kpp;
                            if(kpp.Value==basicPaymentPeriodLength)
                                break;
                        }
                    }
                    SelectedPaymentPeriod = maxpp.Key;

                    IDictionary<IInsurancePeriod, int> dip = new Dictionary<IInsurancePeriod, int>();

                    IInsurancePeriod fristIP = Product.InsurancePeriods[0];

                    KeyValuePair<IInsurancePeriod, int> maxip = new KeyValuePair<IInsurancePeriod, int>(fristIP, GetInsurancePeriodLength(fristIP, Owner.InsurantAge));

                    //这个代码还是存在问题，附加险的付款期可能和保险期不匹配。
                    int basicInsurancePeriodLength = Owner.BasicPolicy.InsurancePeriodLength;

                    foreach (IInsurancePeriod ip in Product.InsurancePeriods)
                    {
                        KeyValuePair<IInsurancePeriod, int> kip = new KeyValuePair<IInsurancePeriod, int>(ip, GetInsurancePeriodLength(ip, Owner.InsurantAge));

                        if (kip.Value <= basicInsurancePeriodLength && kip.Value >= maxpp.Value)
                        {
                            maxip = kip;
                            if (kip.Value == basicPaymentPeriodLength)
                                break;
                        }
                    }

                    SelectedInsurancePeriod = maxip.Key;
                }

            }
        }

        protected virtual int GetPaymentPeriodLength(IPaymentPeriod pp, int age)
        {
            
            int p = 0;
            switch (pp.Style)
            {
                case PaymentPeriodStyle.Once:
                    p = 1;
                    break;
                case PaymentPeriodStyle.Period:
                    p = pp.Value;
                    break;
                case PaymentPeriodStyle.Age:
                    p = pp.Value - age ;
                    break;
                case PaymentPeriodStyle.EqualInsPeriod:
                    p = InsurancePeriodLength;
                    break;
                case PaymentPeriodStyle.EqualBasic:
                    p = Owner.BasicPolicy.PaymentPeriodLength;
                    break;
                case PaymentPeriodStyle.Lifetime:
                    p = InsurancePeriodLength;
                    break;
            }

            //if (p < 0)
            //{
            //    throw new Exception(string.Format("超出保险的最大年龄{0}限制:", pp.Value));
            //}

            return p * OverPaymentPeriod;
        }

        protected virtual int GetInsurancePeriodLength(IInsurancePeriod ip, int age)
        {
            int p = 0;

            switch (ip.Style)
            {
                case InsurancePeriodStyle.Lifetime:
                    p = 999;
                    break;
                case InsurancePeriodStyle.Period:
                    p = ip.Value;
                    break;
                case InsurancePeriodStyle.Age:
                    p = ip.Value - age +1;
                    break;
                case InsurancePeriodStyle.EqualPayPeriod:
                    p = PaymentPeriodLength;
                    break;
                case InsurancePeriodStyle.EqualBasic:
                    p = Owner.BasicPolicy.InsurancePeriodLength;
                    break;
            }

            //return p * OverInsurancePeriod;//再乘以OverInsurancePeriod是不对的，重复了，感觉OverInsurancePeriod这个概念是多余的。
            return p;
        }

        public override PolicyTarget Target { get { return Product.Expander.Target; } }

        public override object Clone()
        {
            Policy tmp = new Policy(this.Owner);

            BaseTools.CopyTo<IPolicy>(this,tmp);

            return tmp;
        }


        //public virtual double[] AllFixFees { get; set; }

    }
}
